//一，将下面异步代码使用promise方式改进
/**
 * setTimeout(function(){
    var a = 'hello'
    setTimeout(function(){
        var b = 'lagou'
        setTimeout(function(){
            var c = 'i love u'
            console.log(a + b + c)
        },10)
    },10)
    
},10)
 */


function fn(value) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(value)
        }, 10);
    })
}

Promise.resolve().then(() => {
    var a = 'hello '; 
    return fn(a, 10)
}).then((value) => {
    var b = value +'lagou ';
    return fn(b, 10)
}).then((value) => {
    var c = value +'I ♥ YOU';
    return fn(c, 10)
}).then((value)=> {
    console.log(value)
})


//基于以下代码完成下面四个练习

const fp = require('lodash/fp')
const { flowRight, isArguments } = require('lodash')
//数据
//horsepower马力，dollar_value 价格， in_stock 库存
const cars = [
    { name:'Ferrari FF' ,  horsepower: 660, dollar_value:700000,  in_stock:true },
    { name:'Jaguar XKR-S' ,  horsepower: 550, dollar_value:132000,  in_stock:false },
    { name:'Spyker c12 Zahato' ,  horsepower: 650, dollar_value:648000,  in_stock:false },
    { name:'Audi R8' ,  horsepower: 525, dollar_value:114200,  in_stock:false },
    { name:'Aston Martin One-77' ,  horsepower: 750, dollar_value:1850000,  in_stock:true },
    { name:'Pagani Huayra' ,  horsepower: 700, dollar_value:1300000,  in_stock:false },
]

//1.使用函数组合fp.flowRight()重新实现下面这个函数

// let isLastInStock = function (cars) {
//     //获取最后一条数据
//     let last_car = fp.last(cars)
//     //获取最后一条数据的in_stock的属性值
//     console.log(fp.prop('in_stock',last_car))
//     return fp.prop('in_stock',last_car)
// }
// isLastInStock(cars)

 let last_car  =  fp.flowRight(fp.prop('in_stock'),fp.last)
 
 console.log(last_car(cars))



//2.使用fp.flowRight(),fp.prop,fp.first()获取第一个car的name


 let first_car = fp.flowRight(fp.prop('name'),fp.first)
 console.log(first_car(cars))

 //3.使用帮助函数_average重构averageDollarValue,使用函数组合的方式实现

  let _average = function(xs) {
      return fp.reduce(fp.add,0,xs) / xs.length
  } // <-无需改动

//  let averageDollarValue = function (cars) {
//      let  dollar_values = fp.map(function(car){
//          return car.dollar_value
//      },cars)
//      return _average(dollar_values)
//  }

// console.log(averageDollarValue(cars))

   let averageDollarValue = function (cars) {
    const f = fp.flowRight(_average,fp.map(fp.prop('dollar_value')))
      return  f(cars)
    } 
    console.log(averageDollarValue(cars))

 //4.使用flowRight写一个sanitizeNames()函数，返回一个下划线链接的小写字符串，把数组中的name转换为这种形式：例如：

//sanitizeNames(["Hello World"]) => ["hello_world"]

//let _underscore = fp.replace(/\w+/g,'_') //<-- 无需改动，并在sanitizeNames 中使用它

function sanitizeNames(word){
  let _underscore = fp.replace(/\s+/g,'_') //<-- 无需改动，并在sanitizeNames 中使用它
  const f = fp.flowRight(_underscore,fp.toLower,fp.map(fp.prop('name')))
  return f(word)
 }
 console.log(sanitizeNames(cars))


//三 基于以下代码，完成后续四个练习

//1.使用fp.add(x,y)和fp.map(f,x)创建一个能让functor里的值增加的函数ex1
//app.js
//const fp = require('lodash/fp')
const { Maybe, Container } = require('./support')

let maybe = Maybe.of([5,6,1])
let ex1 = (num) => {
    //需要你实现的函数
   return maybe.map(fp.map(fp.add(num)))._value
}

console.log(ex1(1))

//2.实现一个函数ex2,能够使用fp.first获得列表的第一个元素

//const fp = require('lodash/fp')
// const { Maybe, Container } = require('./support')

let xs = Container.of(['do','ray','me','fa','so','la','ti','do'])
let ex2 = () => {
    return xs.map(fp.first)._value
}

console.log(ex2())

//3.实现一个函数ex3，使用safeProp 和fp.first找到user的名字的首字母
//const fp = require('lodash/fp')
// const { Maybe, Container } = require('./support')

let safeProp = fp.curry(function(x,o){
    return Maybe.of(o[x])
})

let user = {id:2,name:'Albert'}
let ex3 = (user) => {

    return fp.first(safeProp('name',user)._value)
}
console.log(ex3(user))

//4.使用Maybe重写ex4，不要有if语句
//const fp = require('lodash/fp')
// const { Maybe, Container } = require('./support')

// let ex4 = function(n) {
//     if(n) {
//         return parseInt(n)
//     }
// }

// console.log(ex4(11.33))

let ex4 = function(n) {
    return  Maybe.of(n).map(n => parseInt(n))._value
}

console.log(ex4(22.33))

//四，手写实现MyPRrimise源码
//要求：尽可能还原Promise中的每一个API，并通过注释的方式描述思路和原理。

//promise有3个状态 pending等待,fulfilled成功，rejected失败。
const PENDING = 'pending';
const FULFILLED = 'filfulled';
const REJECTED = 'rejected';

class myPromise{
    //构造函数传入执行器
    constructor(exector){
        //使用trycatch捕抓执行器错误
       try{
         //执行器里有两个方法参数 resolve,reject;
        exector(this.resolve,this.reject)
      } catch(e){
          reject(e) 
         }
    }
     //设置默认状态值
    status = PENDING;
     value = undefined;
     reason = undefined;
     successCallback = [];
     failCallback = [];
     //设置如果不是等待就停止执行
     //设置这里的状态是成功
     //保存传来的值
     //使用while循环成功回调，使用shift方法处理传来的值
    resolve = value => {
       if(this.status  !== PENDING) return;
       this.status = FULFILLED;
       this.value = value;
       while(this.successCallback.length) this.successCallback.shift()();
    }
     //设置如果不是等待就停止执行
     //设置这里的状态是失败
     //保存传来的值
     //使用while循环成功回调，使用shift方法处理传来的值
    reject = reason => {
      if(this.status  !== PENDING) return;
      this.status = REJECTED;
      this.reason = reason;
      while(this.failCallback.length) this.failCallback.shift()();
   }
   //传入then里面的参数是成功回调函数，失败回调函数
   then(successCallback,failCallback){
      //链式调用值判断，如果之前的是空值，会报错，所以这里需要先判断
      successCallback = successCallback ? successCallback : value => value;
      failCallback = failCallback ? failCallback :  reason => { throw reason }
      //链式调用就要返回myPromise对象
      let promise2 = new myPromise((resolve,reject) =>{
      //根据状态判断调用哪个回调 函数
      if(this.status === FULFILLED) {
         //调用使用settimeout异步等待promise2执行完后传入resolvePromise进行下一步操作
         setTimeout(()=>{
            try{
               let v =  successCallback(this.value);
               resolvePromise(promise2,v,resolve,reject);
               } catch(e){
                  reject(e)
               }
            },0)
      } else if(this.status === REJECTED) {
         
         setTimeout(()=>{
            try{
              let v =  failCallback(this.reason);
              resolvePromise(promise2,v,resolve,reject);
               } catch(e){
                 reject(e)
               }
            },0)
      } else{
        //如果不是成功或者失败状态就就是等待状态
        //保存失败 成功的值,由于then可以传入多个值，所以这里使用push
        this.successCallback.push( ()=>{
         setTimeout(()=>{
            try{
            let v =  successCallback(this.value);
            resolvePromise(promise2,v,resolve,reject);
               } catch(e){
               reject(e)
               }
            },0)}
            )
        this.failCallback.push(()=>{  
           setTimeout(()=>{
            try{
            let v =  failCallback(this.reason);
            resolvePromise(promise2,v,resolve,reject);
               } catch(e){
               reject(e)
               }
            },0)}
            )
      }
     })
     return promise2;
   }
   //finally 无论是成功或者失败都会返回值
   //这里的then()返回的是调用finally方法里的值,不使用则返回callback()里的return的值
   finally(callback)
   {
      return this.then(
         value => {
           return myPromise.resolve(callback()).then(() => value )
         },reason => {
           return myPromise.resolve(callback()).then(() => { throw reason } )
         }
      )
   }


//    //传入失败回调的结果
//     catch(){
//        return this.then(undefined,this.failCallback)
//     }
//    //静态成功方法
//    //结果是promise对象，返回结果，不是就让传入的值变成promise对象
//    static resolve(value){
//      if(value instanceof myPromise) return value;
//      return new myPromise((resolve) => {
//          resolve(value)
//      })   
//    }

//    //all静态方法转入array数组
//    static all(array){
//       //设置获取的结果是数组
//       let result = [];
//       let index = 0;
//       return new myPromise((resolve,reject)=>{
//          //addData方法是将array处理后的值存到result里
//          function addData(key,value){
//             result[key] = value
//             index++;
//             //index递增当等于数组长度的时候，将result值传递到resolve 使用promise对象处理
//             if(index === array.length){
//                resolve(result);
//             }
//          }
//          for(let i=0; i<array.length;i++){
//             //判断是 普通值还是promise对象
//             if(array[i] instanceof myPromise){
//                 array[i].then(value =>{ addData(i,value) },reason =>{ reject(reason)})
//             }else{
//                 addData(i,array[i])
//             }
//          }
       
//       })
//    }
// }

// function resolvePromise(promise2,v,resolve,reject){
//    if(promise2 === v) {
//       return reject(new TypeError("循环错误"))
//    }
//    //判断是否是mypromise对象是就返回then方法
//    if(v instanceof myPromise){
//        v.then(valve=>resolve(valve),reason => reject(reason))
//    }else{
//     //是普通值就直接传入resolve
//       resolve(v)
//    }
// }
// module.exports = myPromise;

//test.js

// const myPromise = require('./myPromise2');

//  let promise = new myPromise((resolve,reject)=>{
//     // resolve('success...')
//       reject('fail')
//     //  setTimeout(()=>{
//     //     resolve('success...')
//     //     //reject('fail')
//     //  },2000)
//  })

//  function p1(){
//     return new myPromise((resolve,reject) => {
//         setTimeout(()=>{
//                 resolve('p1...')
//                 //reject('1111')
//              },2000)
//     })
// }

// function p2(){
//     return new myPromise((resolve,reject) => {
//                 resolve('p2...')
              
//     })
// }


// //   promise.then().then().then(value => {
// //         console.log(value,'vallll');
// //     })

// p2().finally(() => {
//     console.log('finally')   
//     return p1();//等待了两秒  
// }).then(value => console.log(value))   

//  myPromise.all(['a','b',p1(),p2(),'c']).then(result => console.log(result))
// myPromise.resolve(100).then(value => console.log(value))
// myPromise.resolve(p1()).then(value => console.log(value)).catch(reason =>console.log(reason))